home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / ofs / ofsAlloc.c < prev    next >
C/C++ Source or Header  |  1991-05-06  |  65KB  |  2,217 lines

  1. /* 
  2.  * ofsAlloc.c --
  3.  *
  4.  *    Block and fragment allocation and truncation.  This code is specific
  5.  *    to 4Kbyte blocks with 1Kbyte fragments.
  6.  *
  7.  * Copyright 1987 Regents of the University of California
  8.  * All rights reserved.
  9.  * Permission to use, copy, modify, and distribute this
  10.  * software and its documentation for any purpose and without
  11.  * fee is hereby granted, provided that the above copyright
  12.  * notice appear in all copies.  The University of California
  13.  * makes no representations about the suitability of this
  14.  * software for any purpose.  It is provided "as is" without
  15.  * express or implied warranty.
  16.  */
  17.  
  18. #ifndef lint
  19. static char rcsid[] = "$Header: /sprite/src/kernel/ofs/RCS/ofsAlloc.c,v 9.14 90/12/11 01:02:20 mgbaker Exp $ SPRITE (Berkeley)";
  20. #endif not lint
  21.  
  22. #include <sprite.h>
  23. #include <fs.h>
  24. #include <fsutil.h>
  25. #include <fscache.h>
  26. #include <fslcl.h>
  27. #include <fsNameOps.h>
  28. #include <fsio.h>
  29. #include <spriteTime.h>
  30. #include <devFsOpTable.h>
  31. #include <fsStat.h>
  32. #include <timer.h>
  33. #include <rpc.h>
  34. #include <proc.h>
  35. #include <string.h>
  36. #include <fsdm.h>
  37. #include <ofs.h>
  38.  
  39. #include <stdio.h>
  40.  
  41. /*
  42.  * Each domain, which is a separate piece of disk, is locked
  43.  * during allocation.
  44.  */
  45. #define LOCKPTR (&ofsPtr->dataBlockLock)
  46.  
  47. /*
  48.  * A table indexed by a 4 bit value is used by the allocation routine to 
  49.  * quickly determine the location of 1, 2, and 3K fragments in a byte.  
  50.  * The indices of the fragments start from 0.  If there is no such fragment in 
  51.  * the byte then a -1 is used.
  52.  */
  53.  
  54. static int fragTable[16][OFS_NUM_FRAG_SIZES] = {
  55. /* 0000 */ {-1, -1, -1},
  56. /* 0001 */ {-1, -1, 0},
  57. /* 0010 */ {3, 0, -1},
  58. /* 0011 */ {-1, 0, -1},
  59. /* 0100 */ {0, 2, -1},
  60. /* 0101 */ {0, -1, -1},
  61. /* 0110 */ {0, -1, -1},
  62. /* 0111 */ {0, -1, -1},
  63. /* 1000 */ {-1, -1, 1},
  64. /* 1001 */ {-1, 1, -1},
  65. /* 1010 */ {1, -1, -1},
  66. /* 1011 */ {1, -1, -1},
  67. /* 1100 */ {-1, 2, -1},
  68. /* 1101 */ {2, -1, -1},
  69. /* 1110 */ {3, -1, -1},
  70. /* 1111 */ {-1, -1, -1}
  71. };
  72.  
  73. /*
  74.  * Array to provide the ability to set and extract bits out of a bitmap byte.
  75.  */
  76.  
  77. static unsigned char bitMasks[8] = {0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1};
  78.  
  79. /*
  80.  * Macros to get to the 4-bit fragment masks of the two 4K blocks that are 
  81.  * stored in a byte.
  82.  */
  83.  
  84. #define    UpperBlockFree(byte)    (((byte) & 0xf0) == 0x00)
  85. #define    LowerBlockFree(byte)    (((byte) & 0x0f) == 0x00)
  86. #define    BothBlocksFree(byte)    (((byte) & 0xff) == 0x00)
  87. #define    GetUpperFragMask(byte) (((byte) >> 4) & 0x0f)
  88. #define    GetLowerFragMask(byte) ((byte) & 0x0f)
  89.  
  90. /*
  91.  * Macro to get a pointer into the bit map for a particular block.
  92.  */
  93.  
  94. #define    BlockToCylinder(ofsPtr, blockNum) \
  95.  (unsigned int) (blockNum) / (ofsPtr)->headerPtr->geometry.blocksPerCylinder
  96.  
  97. #define    GetBitmapPtr(ofsPtr, blockNum) \
  98.     &((ofsPtr)->dataBlockBitmap[BlockToCylinder(ofsPtr, blockNum) * \
  99.           (ofsPtr)->bytesPerCylinder + \
  100.           ((unsigned int) ((blockNum) % \
  101.           (ofsPtr)->headerPtr->geometry.blocksPerCylinder) / 2)])
  102.  
  103. #define    LAST_FRAG     (FS_FRAGMENTS_PER_BLOCK - 1)
  104. #define    FRAG_OFFSET_MASK (FS_FRAGMENTS_PER_BLOCK - 1)
  105.  
  106. /*
  107.  * Size of a fragment (1K).
  108.  */
  109. #define FRAG_SIZE (FS_BLOCK_SIZE / FS_FRAGMENTS_PER_BLOCK)
  110.  
  111. /*
  112.  * Percent of disk to keep free.
  113.  */
  114. int    ofsPercentFree = 10;
  115.  
  116. /*
  117.  * Block allocation style (settable with FS_SET_ALLOC_GAP Fs_Command)
  118.  *    CONTIGUOUS    Blocks are allocated coniguously, beginning at the
  119.  *            beginning of the cylinder.
  120.  *    SKIP_ONE    Blocks are allocated with one free block between
  121.  *            each allocated block.  The extra block gives the
  122.  *            software time to generate a new disk request
  123.  *            before the next allocated block rotates past the head.
  124.  */
  125. #define CONTIGUOUS    0
  126. #define SKIP_ONE    1
  127.  
  128. int ofs_AllocGap = CONTIGUOUS;
  129.  
  130. /*
  131.  * Forward references.
  132.  */
  133. static void FindBlockInt _ARGS_((int hashSeed, Ofs_Domain *ofsPtr,
  134.         int nearBlock, Boolean allocate, int *blockNumPtr, 
  135.         unsigned char **bitmapPtrPtr));
  136. static ReturnStatus UpgradeFragment _ARGS_((Ofs_Domain *ofsPtr, 
  137.         Fsio_FileIOHandle *handlePtr, OfsBlockIndexInfo *indexInfoPtr,
  138.         int curLastBlock, int newLastFrag, Boolean dontWriteThru, 
  139.         int dontBlock, Boolean *dirtiedIndexPtr));
  140. static ReturnStatus AllocateBlock _ARGS_((Fsio_FileIOHandle *handlePtr, 
  141.         Fsdm_FileDescriptor *descPtr, OfsBlockIndexInfo *indexInfoPtr,
  142.         int newLastByte, int curLastBlock, int dontBlock,
  143.         Boolean *dirtiedIndexPtr));
  144. static ReturnStatus FragToBlock _ARGS_((Ofs_Domain *ofsPtr, 
  145.         Fsio_FileIOHandle *handlePtr, int blockNum, int dontBlock));
  146. static void PutInBadBlockFile _ARGS_((Fsio_FileIOHandle *handlePtr, 
  147.         Ofs_Domain *ofsPtr, int blockNum));
  148.  
  149.  
  150. /*
  151.  *----------------------------------------------------------------------
  152.  *
  153.  * OfsBlockAllocInit() --
  154.  *
  155.  *    Initialize the data structure needed for block allocation for the
  156.  *    given domain on a local disk.
  157.  *
  158.  * Results:
  159.  *    None.
  160.  *
  161.  * Side effects:
  162.  *    Memory is allocated for the bit map, the cylinder map and the fragment
  163.  *    lists.  The bit map is read in and the cylinder map and fragment lists 
  164.  *    are initialized.
  165.  *
  166.  *----------------------------------------------------------------------
  167.  */
  168. ReturnStatus
  169. OfsBlockAllocInit(ofsPtr)
  170.     register    Ofs_Domain    *ofsPtr;    /* Domain to initialize block
  171.                          * allocation for. */
  172. {
  173.     int                blocksPerCylinder;
  174.     int                bitmapBytes;
  175.     register    unsigned char     *bitmapPtr;
  176.     register    OfsCylinder    *cylinderPtr;
  177.     register    OfsFragment    *fragPtr;
  178.     register    int        i;
  179.     register    int        j;
  180.     register    int        k;
  181.     int                *fragOffsetPtr;
  182.     ReturnStatus        status;
  183.  
  184.     Sync_LockInitDynamic(&(ofsPtr->dataBlockLock), "Fs:ofsDataBlockLock");
  185.     /*
  186.      * Ensure some free disk space for disk block allocation.
  187.      */
  188.     ofsPtr->minKFree =
  189.     (ofsPtr->headerPtr->dataBlocks * FS_FRAGMENTS_PER_BLOCK) /
  190.                 ofsPercentFree;
  191.  
  192.     blocksPerCylinder = ofsPtr->headerPtr->geometry.blocksPerCylinder;
  193.  
  194.     /*
  195.      * Allocate the bit map.
  196.      */
  197.     bitmapBytes = (unsigned int) (blocksPerCylinder + 1) / 2;
  198.     ofsPtr->bytesPerCylinder = bitmapBytes;
  199.     ofsPtr->dataBlockBitmap = (unsigned char *) 
  200.     malloc(ofsPtr->headerPtr->bitmapBlocks * FS_BLOCK_SIZE);
  201.  
  202.     /* 
  203.      * Read in the bit map.  The Block I/O interface is based on 1K blocks,
  204.      * but the header information is in terms of 4K blocks.
  205.      */
  206.     status = OfsDeviceBlockIO(ofsPtr, FS_READ, 
  207.         ofsPtr->headerPtr->bitmapOffset * 4, 
  208.         ofsPtr->headerPtr->bitmapBlocks * 4,
  209.         (Address) ofsPtr->dataBlockBitmap);
  210.     if (status != SUCCESS) {
  211.     printf(
  212.         "OfsBlockAllocInit: Could not read data block bitmap.\n");
  213.     return(status);
  214.     }
  215.  
  216.     /*
  217.      * Initialize the 3 fragment lists (1K, 2K and 3K).
  218.      */
  219.     for (i = 0; i < OFS_NUM_FRAG_SIZES; i++) {
  220.     ofsPtr->fragLists[i] = (List_Links *) malloc(sizeof(List_Links));
  221.     List_Init(ofsPtr->fragLists[i]);
  222.     }
  223.  
  224.     /*
  225.      * Allocate an array cylinder information.
  226.      */
  227.     ofsPtr->cylinders = (OfsCylinder *) 
  228.     malloc(sizeof(OfsCylinder) * ofsPtr->headerPtr->dataCylinders);
  229.  
  230.     /*
  231.      * Now go through the bit map finding all of the fragments and putting
  232.      * them onto the appropriate lists.  Also determine cylinder information.
  233.      */
  234.     bitmapPtr = ofsPtr->dataBlockBitmap;
  235.     cylinderPtr = ofsPtr->cylinders;
  236.     for (i = 0; i < ofsPtr->headerPtr->dataCylinders; i++, cylinderPtr++) {
  237.     cylinderPtr->blocksFree = 0;
  238.     for (j = 0; j < bitmapBytes; j++, bitmapPtr++) {
  239.         if (UpperBlockFree(*bitmapPtr)) {
  240.         cylinderPtr->blocksFree++;
  241.         } else {
  242.         fragOffsetPtr = fragTable[GetUpperFragMask(*bitmapPtr)];
  243.         for (k = 0; k < OFS_NUM_FRAG_SIZES; k++, fragOffsetPtr++) {
  244.             if (*fragOffsetPtr != -1) {
  245.             fragPtr = (OfsFragment *) malloc(sizeof(OfsFragment));
  246.             List_Insert((List_Links *) fragPtr, 
  247.                     LIST_ATREAR(ofsPtr->fragLists[k]));
  248.             fragPtr->blockNum = i * blocksPerCylinder + j * 2;
  249.             }
  250.         }
  251.         }
  252.  
  253.         /*
  254.          * There may be an odd number of blocks per cylinder.  If so
  255.          * and are at the end of the bit map for this cylinder, then
  256.          * we can bail out now.
  257.          */
  258.  
  259.         if (j == (bitmapBytes - 1) && (blocksPerCylinder & 0x1)) {
  260.         continue;
  261.         }
  262.  
  263.         if (LowerBlockFree(*bitmapPtr)) {
  264.         cylinderPtr->blocksFree++;
  265.         } else {
  266.         fragOffsetPtr = fragTable[GetLowerFragMask(*bitmapPtr)];
  267.         for (k = 0; k < OFS_NUM_FRAG_SIZES; k++, fragOffsetPtr++) {
  268.             if (*fragOffsetPtr != -1) {
  269.             fragPtr = (OfsFragment *) malloc(sizeof(OfsFragment));
  270.             List_Insert((List_Links *) fragPtr, 
  271.                     LIST_ATREAR(ofsPtr->fragLists[k]));
  272.             fragPtr->blockNum = i * blocksPerCylinder + j * 2 + 1;
  273.             }
  274.         }
  275.         }
  276.     }
  277.     }
  278.  
  279.     return(SUCCESS);
  280. }
  281.  
  282. /*
  283.  *----------------------------------------------------------------------
  284.  *
  285.  * Ofs_BlockAllocate --
  286.  *
  287.  *    Allocate disk space for the given file.  This routine only allocates
  288.  *    one block beginning at offset and going for numBytes.   If 
  289.  *    offset + numBytes crosses a block boundary then a panic will occur.
  290.  *
  291.  * Results:
  292.  *    None.
  293.  *
  294.  * Side effects:
  295.  *    The file descriptor is modified to contain pointers to the allocated
  296.  *    blocks.  Also *blockAddrPtr is set to the block that was allocated.
  297.  *
  298.  *----------------------------------------------------------------------
  299.  */
  300. ReturnStatus
  301. Ofs_BlockAllocate(domainPtr, handlePtr, offset, numBytes, flags, blockAddrPtr,
  302.         newBlockPtr)
  303.     Fsdm_Domain        *domainPtr;    /* Domain of file. */
  304.     register Fsio_FileIOHandle *handlePtr;    /* Local file handle. */
  305.     int         offset;        /* Offset to allocate at. */
  306.     int         numBytes;    /* Number of bytes to allocate. */
  307.     int            flags;        /* FSCACHE_DONT_BLOCK */
  308.     int            *blockAddrPtr;     /* Disk address of block allocated. */
  309.     Boolean        *newBlockPtr;    /* TRUE if there was no block allocated
  310.                      * before. */
  311. {
  312.     Ofs_Domain            *ofsPtr = OFS_PTR_FROM_DOMAIN(domainPtr);
  313.     register Fsdm_FileDescriptor    *descPtr;
  314.     register int        blockNum;
  315.     OfsBlockIndexInfo        indexInfo;
  316.     int                newLastByte;
  317.     int                curLastBlock;
  318.     int                curLastFrag;
  319.     Boolean            dirtiedIndex = FALSE;
  320.     ReturnStatus        status;
  321.  
  322.     descPtr = handlePtr->descPtr;
  323.  
  324.     *blockAddrPtr = FSDM_NIL_INDEX;
  325.     newLastByte = offset + numBytes - 1;
  326.     blockNum = (unsigned int) offset / FS_BLOCK_SIZE;
  327.  
  328.     if ((unsigned int) (newLastByte) / FS_BLOCK_SIZE != blockNum) {
  329.     panic("OfsFileAllocate: Trying to allocate more than one block\n");
  330.     }
  331.  
  332.     if (descPtr->lastByte != -1) {
  333.     curLastBlock = (unsigned int) (descPtr->lastByte) / FS_BLOCK_SIZE;
  334.     } else {
  335.     curLastBlock = -1;
  336.     }
  337.  
  338.     /*
  339.      * If are allocating past the current last block in the file, then
  340.      * make the last block into a full block.
  341.      */
  342.     if (curLastBlock != -1 && curLastBlock < FSDM_NUM_DIRECT_BLOCKS &&
  343.         blockNum > curLastBlock) {
  344.     curLastFrag = (unsigned int) (descPtr->lastByte & FS_BLOCK_OFFSET_MASK)
  345.                 / FS_FRAGMENT_SIZE;
  346.     if (curLastFrag < LAST_FRAG) {
  347.         /*
  348.          * Upgrade the fragment to a full block.
  349.          */
  350.         status = FragToBlock(ofsPtr, handlePtr, curLastBlock, flags);
  351.         if (status != SUCCESS) {
  352.         return(status);
  353.         }
  354.     }
  355.     }
  356.  
  357.     /*
  358.      * Set up the indexing structure here.
  359.      */
  360.     if (blockNum == 0) {
  361.     /*
  362.      * This is the first block of the file so there is no previous
  363.      * block.
  364.      */
  365.     status = OfsGetFirstIndex(ofsPtr, handlePtr, blockNum, &indexInfo,
  366.                  OFS_ALLOC_INDIRECT_BLOCKS);
  367.     if (status != SUCCESS) {
  368.         return(status);
  369.     }
  370.     } else {
  371.     /*
  372.      * This is not the first block in the file, so determine the
  373.      * previous block and then go to the first block.
  374.      */
  375.     status = OfsGetFirstIndex(ofsPtr, handlePtr, blockNum - 1, &indexInfo,
  376.                  OFS_ALLOC_INDIRECT_BLOCKS);
  377.     if (status != SUCCESS) {
  378.         return(status);
  379.     }
  380.     status = OfsGetNextIndex(handlePtr, &indexInfo, FALSE);
  381.     if (status != SUCCESS) {
  382.         OfsEndIndex(handlePtr, &indexInfo, FALSE);
  383.         return(status);
  384.     }
  385.     }
  386.  
  387.     *newBlockPtr = (*indexInfo.blockAddrPtr == FSDM_NIL_INDEX);
  388.  
  389.     /*
  390.      * Allocate space for the block.
  391.      */
  392.  
  393.     status = AllocateBlock(handlePtr, descPtr, &indexInfo, newLastByte, 
  394.                curLastBlock, flags, &dirtiedIndex);
  395.  
  396.     if (status == SUCCESS) {
  397.     *blockAddrPtr = *indexInfo.blockAddrPtr;
  398.     }
  399.  
  400.     OfsEndIndex(handlePtr, &indexInfo, dirtiedIndex);
  401.  
  402.     if (status != SUCCESS) {
  403.     return(status);
  404.     }
  405.     /*
  406.      * Update the size of the file.  A firstByte of 0 is used in
  407.      * named pipes to note that there is data in the pipe.
  408.      * NOTE:  We can almost check the stream flags FS_CONSUME here,
  409.      * except that when remote clients flush back named pipe blocks
  410.      * they clear that flag so we the server treat it like a regular
  411.      * file and don't consume or append.  Hence the check against fileType.
  412.      */
  413.  
  414.     if (newLastByte > descPtr->lastByte) {
  415.     descPtr->lastByte = newLastByte;
  416.     }
  417.     if (descPtr->firstByte == -1 && 
  418.     ((descPtr->fileType == FS_NAMED_PIPE) ||
  419.      (descPtr->fileType == FS_PSEUDO_DEV) ||
  420.      (descPtr->fileType == FS_XTRA_FILE))) {
  421.     descPtr->firstByte = 0;
  422.     }
  423.     descPtr->descModifyTime = Fsutil_TimeInSeconds();
  424.     descPtr->flags |= (FSDM_FD_INDEX_DIRTY|FSDM_FD_SIZE_DIRTY);
  425.     return(SUCCESS);
  426. }
  427.  
  428.  
  429. /*
  430.  *----------------------------------------------------------------------
  431.  *
  432.  * Ofs_FileTrunc --
  433.  *
  434.  *    Shorten a file to length bytes.  This updates the descriptor
  435.  *    and may free blocks and indirect blocks from the end of the file.
  436.  *
  437.  * Results:
  438.  *    Error if had problem with indirect blocks, otherwise SUCCESS.
  439.  *
  440.  * Side effects:
  441.  *    Any allocated blocks after the given size are deleted.
  442.  *
  443.  *----------------------------------------------------------------------
  444.  */
  445. /*ARGSUSED*/
  446. ReturnStatus
  447. Ofs_FileTrunc(domainPtr, handlePtr, size, delete)
  448.     Fsdm_Domain        *domainPtr;
  449.     Fsio_FileIOHandle    *handlePtr;    /* File to truncate. */
  450.     int            size;        /* Size to truncate the file to. */
  451.     Boolean        delete;        /* TRUE if Truncate for delete. */
  452. {
  453.     register Ofs_Domain     *ofsPtr = OFS_PTR_FROM_DOMAIN(domainPtr);
  454.     register Fsdm_FileDescriptor     *descPtr;
  455.     int                firstBlock;
  456.     int                firstFrag = 0;
  457.     int                lastBlock;
  458.     int                lastFrag;
  459.     ReturnStatus        status = SUCCESS;
  460.     OfsBlockIndexInfo        indexInfo;
  461.     int                newLastByte;
  462.     int                savedLastByte;
  463.     int                flags;
  464.     Boolean            dirty = FALSE;
  465.     int                fragsToFree;
  466.  
  467.     descPtr = handlePtr->descPtr;
  468.  
  469.     savedLastByte = descPtr->lastByte;
  470.  
  471.     newLastByte = size - 1;
  472.     if (descPtr->lastByte <= newLastByte) {
  473.     status = SUCCESS;
  474.     goto exit;
  475.     }
  476.  
  477.     /*
  478.      * Determine the first block and number of fragments in the first block.
  479.      * This is called from the pipe trunc routine if its length is zero,
  480.      * hence the check against firstByte here.
  481.      */
  482.  
  483.     if (descPtr->firstByte >= 0) {
  484.     firstBlock = (unsigned int) descPtr->firstByte / FS_BLOCK_SIZE;
  485.     } else if (newLastByte == -1) {
  486.     firstBlock = 0;
  487.     } else {
  488.     firstBlock = (unsigned int) newLastByte / FS_BLOCK_SIZE;
  489.     firstFrag = (unsigned int) (newLastByte & FS_BLOCK_OFFSET_MASK) / 
  490.                     FS_FRAGMENT_SIZE;
  491.     }
  492.  
  493.     /*
  494.      * Determine the last block and the number of fragments in it.
  495.      */
  496.  
  497.     lastBlock = (unsigned int) descPtr->lastByte / FS_BLOCK_SIZE;
  498.     if (lastBlock >= FSDM_NUM_DIRECT_BLOCKS) {
  499.     lastFrag = LAST_FRAG;
  500.     } else {
  501.     lastFrag = (descPtr->lastByte & FS_BLOCK_OFFSET_MASK)/FS_FRAGMENT_SIZE;
  502.     }
  503.  
  504.     /*
  505.      * Determine if the file is already short enough in terms of blocks.
  506.      */
  507.  
  508.     if (newLastByte != -1 && firstBlock == lastBlock && 
  509.     (lastFrag <= firstFrag || firstBlock >= FSDM_NUM_DIRECT_BLOCKS)) {
  510.     if (newLastByte < descPtr->lastByte) {
  511.         descPtr->lastByte = newLastByte;
  512.         descPtr->descModifyTime = Fsutil_TimeInSeconds();
  513.         descPtr->flags |= FSDM_FD_SIZE_DIRTY;
  514.     }
  515.     status = SUCCESS;
  516.     goto exit;
  517.     }
  518.  
  519.     flags = OFS_DELETE_INDIRECT_BLOCKS;
  520.     if (newLastByte == -1) {
  521.     flags |= OFS_DELETE_EVERYTHING;
  522.     }
  523.  
  524.     /*
  525.      * Loop through the blocks deleting them.
  526.      */
  527.     status = OfsGetFirstIndex(ofsPtr, handlePtr, firstBlock, &indexInfo, flags);
  528.     if (status != SUCCESS) {
  529.     printf( "Ofs_FileTrunc: Status %x setting up index\n",
  530.           status);
  531.     goto exit;
  532.     }
  533.     while (TRUE) {
  534.     if (indexInfo.blockAddrPtr == (int *) NIL ||
  535.         *indexInfo.blockAddrPtr == FSDM_NIL_INDEX) {
  536.         goto nextBlock;
  537.     }
  538.  
  539.     dirty = FALSE;
  540.  
  541.     if (newLastByte == -1) {
  542.         /*
  543.          * The file is being made empty.
  544.          */
  545.         if (indexInfo.blockNum == lastBlock && lastFrag < LAST_FRAG) {
  546.         OfsFragFree(ofsPtr, lastFrag + 1, 
  547.             (int) (*indexInfo.blockAddrPtr / FS_FRAGMENTS_PER_BLOCK),
  548.             *indexInfo.blockAddrPtr & FRAG_OFFSET_MASK);
  549.         descPtr->numKbytes -= lastFrag + 1;
  550.         } else {
  551.         OfsBlockFree(ofsPtr, 
  552.             (int) (*indexInfo.blockAddrPtr / FS_FRAGMENTS_PER_BLOCK));
  553.         descPtr->numKbytes -= FS_FRAGMENTS_PER_BLOCK;
  554.         }
  555.         *indexInfo.blockAddrPtr = FSDM_NIL_INDEX;
  556.     } else if (indexInfo.blockNum == firstBlock) {
  557.         /*
  558.          * The first block that we truncate becomes the last block in
  559.          * the file.  If we are still in direct blocks we have to
  560.          * chop this (new last block) into the right number of fragments.
  561.          */
  562.         if (firstBlock >= FSDM_NUM_DIRECT_BLOCKS) {
  563.         goto nextBlock;
  564.         }
  565.         if (firstBlock != lastBlock) {
  566.         fragsToFree = LAST_FRAG - firstFrag;
  567.         } else {
  568.         fragsToFree = lastFrag - firstFrag;
  569.         }
  570.         if (fragsToFree > 0) {
  571.         OfsFragFree(ofsPtr, fragsToFree,
  572.               (int) (*indexInfo.blockAddrPtr / FS_FRAGMENTS_PER_BLOCK),
  573.                 (*indexInfo.blockAddrPtr & FRAG_OFFSET_MASK)
  574.                  + firstFrag + 1);
  575.         descPtr->numKbytes -= fragsToFree;
  576.         }
  577.     } else if (indexInfo.blockNum >= FSDM_NUM_DIRECT_BLOCKS || 
  578.                indexInfo.blockNum < lastBlock || lastFrag == LAST_FRAG) {
  579.         /*
  580.          * This is a full block so delete it.
  581.          */
  582.         OfsBlockFree(ofsPtr, 
  583.          (int) (*indexInfo.blockAddrPtr / FS_FRAGMENTS_PER_BLOCK));
  584.         descPtr->numKbytes -= FS_FRAGMENTS_PER_BLOCK;
  585.         *indexInfo.blockAddrPtr = FSDM_NIL_INDEX;
  586.     } else {
  587.         /*
  588.          * Delete a fragment.  Only get here if are on the last block in 
  589.          * the file.
  590.          */
  591.         OfsFragFree(ofsPtr, lastFrag + 1, 
  592.           (int) (*indexInfo.blockAddrPtr / FS_FRAGMENTS_PER_BLOCK),
  593.             *indexInfo.blockAddrPtr & FRAG_OFFSET_MASK);
  594.         descPtr->numKbytes -= lastFrag + 1;
  595.         *indexInfo.blockAddrPtr = FSDM_NIL_INDEX;
  596.     }
  597.  
  598.     dirty = TRUE;
  599.  
  600. nextBlock:
  601.  
  602.     if (indexInfo.blockNum == lastBlock) {
  603.         break;
  604.     }
  605.  
  606.     status = OfsGetNextIndex(handlePtr, &indexInfo, dirty);
  607.     if (status != SUCCESS) {
  608.         printf( "Ofs_FileTrunc: Could not truncate file.\n");
  609.         OfsEndIndex(handlePtr, &indexInfo, FALSE);
  610.         goto exit;
  611.     }
  612.     }
  613.  
  614.     OfsEndIndex(handlePtr, &indexInfo, dirty);
  615.  
  616.     descPtr->lastByte = newLastByte;
  617.     descPtr->descModifyTime = Fsutil_TimeInSeconds();
  618.     descPtr->flags |= FSDM_FD_SIZE_DIRTY;
  619.  
  620. exit:
  621.     /*
  622.      * Make sure we really deleted the file if size is zero.
  623.      */
  624.     if (size == 0) {
  625.     register int index;
  626.  
  627.     for (index=0 ; index < FSDM_NUM_DIRECT_BLOCKS ; index++) {
  628.         if (descPtr->direct[index] != FSDM_NIL_INDEX) {
  629.         printf("Ofs_FileTrunc abandoning (direct) block %d in <%d,%d> \"%s\" savedLastByte %d\n",
  630.             descPtr->direct[index],
  631.             handlePtr->hdr.fileID.major, handlePtr->hdr.fileID.minor,
  632.             Fsutil_HandleName((Fs_HandleHeader *)handlePtr),
  633.             savedLastByte);
  634.         descPtr->direct[index] = FSDM_NIL_INDEX;
  635.         }
  636.     }
  637.     for (index = 0 ; index <= 2 ; index++) {
  638.         if (descPtr->indirect[index] != FSDM_NIL_INDEX) {
  639.         printf("Ofs_FileTrunc abandoning (indirect) block %d in <%d,%d> \"%s\" savedLastByte %d\n",
  640.             descPtr->indirect[index], 
  641.             handlePtr->hdr.fileID.major, handlePtr->hdr.fileID.minor,
  642.             Fsutil_HandleName((Fs_HandleHeader *)handlePtr),
  643.             savedLastByte);
  644.         descPtr->indirect[index] = FSDM_NIL_INDEX;
  645.         }
  646.     }
  647.     }
  648.     return(status);
  649. }
  650.  
  651.  
  652.  
  653.  
  654. /*
  655.  *----------------------------------------------------------------------
  656.  *
  657.  * OfsWriteBackDataBlockBitmap --
  658.  *
  659.  *    Write the data block bit map to disk.
  660.  *
  661.  * Results:
  662.  *    None.
  663.  *
  664.  * Side effects:
  665.  *    None.
  666.  *
  667.  *----------------------------------------------------------------------
  668.  */
  669. ENTRY ReturnStatus
  670. OfsWriteBackDataBlockBitmap(ofsPtr)
  671.     register    Ofs_Domain    *ofsPtr;    /* Domain for which to write 
  672.                          * back the bitmap. */
  673. {
  674.     ReturnStatus    status;
  675.  
  676.     LOCK_MONITOR;
  677.  
  678.     status = OfsDeviceBlockIO(ofsPtr, FS_WRITE, 
  679.             ofsPtr->headerPtr->bitmapOffset * 4, 
  680.             ofsPtr->headerPtr->bitmapBlocks * 4,
  681.             (Address) ofsPtr->dataBlockBitmap);
  682.     if (status != SUCCESS) {
  683.     printf( "OfsWriteBackDataBlockBitmap: Could not write out data block bitmap.\n");
  684.     }
  685.  
  686.     UNLOCK_MONITOR;
  687.     return(status);
  688. }
  689.  
  690.  
  691. /*
  692.  *----------------------------------------------------------------------
  693.  *
  694.  * OfsWriteBackSummaryInfo --
  695.  *
  696.  *    Write summary info to disk.
  697.  *
  698.  * Results:
  699.  *    None.
  700.  *
  701.  * Side effects:
  702.  *    None.
  703.  *
  704.  *----------------------------------------------------------------------
  705.  */
  706. ENTRY ReturnStatus
  707. OfsWriteBackSummaryInfo(ofsPtr)
  708.     register    Ofs_Domain    *ofsPtr;    /* Domain for which to write 
  709.                          * back the bitmap. */
  710. {
  711.     ReturnStatus    status;
  712.     Fs_IOParam        io;
  713.     Fs_IOReply        reply;
  714.  
  715.     LOCK_MONITOR;
  716.  
  717.     bzero((Address)&io, sizeof(io));
  718.     bzero((Address)&reply, sizeof(reply));
  719.     io.buffer = (Address)ofsPtr->summaryInfoPtr;
  720.     io.length = DEV_BYTES_PER_SECTOR;
  721.     io.offset = ofsPtr->summarySector * DEV_BYTES_PER_SECTOR;
  722.     status = (*devFsOpTable[DEV_TYPE_INDEX(ofsPtr->headerPtr->device.type)].write)
  723.         (&ofsPtr->headerPtr->device, &io, &reply); 
  724.     if (status != SUCCESS) {
  725.     printf("OfsWriteBackSummaryInfo: Could not write out summary info.\n");
  726.     }
  727.     if (status == GEN_NO_PERMISSION) {
  728.     printf("OfsWriteBackSummaryInfo: Disk is write-protected.\n");
  729.     status = SUCCESS;
  730.     }
  731.     UNLOCK_MONITOR;
  732.     return(status);
  733. }
  734.  
  735.  
  736. /*
  737.  *----------------------------------------------------------------------
  738.  *
  739.  * SelectCylinderInt --
  740.  *
  741.  *    Find a cylinder to use to allocate a block.  The search starts
  742.  *    with cylinderNum.  If it is full then it searches neighboring 
  743.  *    cylinders until it finds a cylinder with a free block.
  744.  *
  745.  * Results:
  746.  *    A cylinder number that contains a free block, -1 if none found.
  747.  *
  748.  * Side effects:
  749.  *    The free count on the found cylinder is decremented.
  750.  *
  751.  *----------------------------------------------------------------------
  752.  */
  753.  
  754. INTERNAL int
  755. SelectCylinderInt(hashSeed, ofsPtr, cylinderNum)
  756.     int                hashSeed;    /* Seed for the hash, usually
  757.                          * the file number. */
  758.     register    Ofs_Domain    *ofsPtr;    /* Domain to select cylinder 
  759.                          * from. */
  760.     int                cylinderNum;    /* Cylinder to try first, -1
  761.                          * if no preferred cylinder. */
  762. {
  763.     register    int        i;
  764.     register    OfsCylinder    *cylinderPtr;
  765.  
  766.     if (cylinderNum == -1) {
  767.     /*
  768.      * Do a random hash to find the starting point to allocate at.
  769.      */
  770.     fs_Stats.alloc.cylHashes++;
  771.     cylinderNum = ((hashSeed * 1103515245 + 12345) & 0x7fffffff) %
  772.                 ofsPtr->headerPtr->dataCylinders;
  773.     }
  774.  
  775.     /*
  776.      * Search forward starting at the desired cylinder.
  777.      */
  778.  
  779.     for (i = cylinderNum, cylinderPtr = &(ofsPtr->cylinders[cylinderNum]); 
  780.      i < ofsPtr->headerPtr->dataCylinders;
  781.      i++, cylinderPtr++) {
  782.     fs_Stats.alloc.cylsSearched++;
  783.     if (cylinderPtr->blocksFree > 0) {
  784.         ofsPtr->cylinders[i].blocksFree--;
  785.         return(i);
  786.     }
  787.     }
  788.  
  789.     /*
  790.      * No block forward from desired cylinder so search backward.
  791.      */
  792.  
  793.     for (i = cylinderNum - 1, 
  794.         cylinderPtr = &(ofsPtr->cylinders[cylinderNum - 1]);
  795.      i >= 0;
  796.      i--, cylinderPtr--) {
  797.     fs_Stats.alloc.cylsSearched++;
  798.     if (cylinderPtr->blocksFree > 0) {
  799.         ofsPtr->cylinders[i].blocksFree--;
  800.         return(i);
  801.     }
  802.     }
  803.  
  804.     return(-1);
  805. }
  806.  
  807.  
  808. /*
  809.  *----------------------------------------------------------------------
  810.  *
  811.  * FindBlockInt --
  812.  *
  813.  *    Search the bit map starting at the given cylinder for a free block.
  814.  *
  815.  * Results:
  816.  *    A logical 4K block number for the disk where the first data block 
  817.  *    is block 0 and a pointer into the bitmap for the block.
  818.  *
  819.  * Side effects:
  820.  *    If the allocate flag is set then the bit map is modified.
  821.  *
  822.  *----------------------------------------------------------------------
  823.  */
  824.  
  825. INTERNAL static void
  826. FindBlockInt(hashSeed, ofsPtr, nearBlock, allocate, blockNumPtr, 
  827.          bitmapPtrPtr)
  828.     int            hashSeed;    /* Seed for cylinder hash. */
  829.     register Ofs_Domain  *ofsPtr;     /* Domain to allocate blocks in. */
  830.     int            nearBlock;      /* Block number where this block should
  831.                      * be near. */
  832.     Boolean        allocate;       /* TRUE if allocating full block, FALSE
  833.                      * if intend to fragment block. */
  834.     int            *blockNumPtr;      /* Block number that was found. */
  835.     unsigned char    **bitmapPtrPtr;    /* Bit map entry that corresponds to
  836.                      * the block. */
  837. {
  838.     unsigned char *bitmapPtr;
  839.     int       blockNum;
  840.     int       block;
  841.     int       startingBlockOffset;
  842.     int               blocksPerCylinder;
  843.     int               mask;
  844.     int               cylinderNum;
  845.  
  846.     blocksPerCylinder = ofsPtr->headerPtr->geometry.blocksPerCylinder;
  847.     if (nearBlock != -1) {
  848.     cylinderNum = ((unsigned int) nearBlock) / blocksPerCylinder;
  849.     startingBlockOffset = ((unsigned int) nearBlock) % blocksPerCylinder;
  850.     } else {
  851.     cylinderNum = -1;
  852.     startingBlockOffset = -1;
  853.     }
  854.     cylinderNum = SelectCylinderInt(hashSeed, ofsPtr, cylinderNum);
  855.     if (cylinderNum == -1) {
  856.     *blockNumPtr = -1;
  857.     return;
  858.     }
  859.     if (ofs_AllocGap == 0) {
  860.     /*
  861.      * CONTIGUOUS allocation.
  862.      * This is the original code that simply starts at the beginning
  863.      * of the cylinder and stops when it finds a free block.
  864.      */
  865.     bitmapPtr = 
  866.       &(ofsPtr->dataBlockBitmap[cylinderNum * ofsPtr->bytesPerCylinder]);
  867.     blockNum = cylinderNum * blocksPerCylinder;
  868.     while (TRUE) {
  869.         fs_Stats.alloc.cylBitmapSearches++;
  870.         if (UpperBlockFree(*bitmapPtr)) {
  871.         mask = 0xf0;
  872.         break;
  873.         }
  874.         if (LowerBlockFree(*bitmapPtr)) {
  875.         mask = 0x0f;
  876.         blockNum++;
  877.         break;
  878.         }
  879.         bitmapPtr++;
  880.         blockNum += 2;
  881.     }
  882.     } else {
  883.     /*
  884.      * SKIP BLOCK allocation.
  885.      * startingBlockOffset is the offset of the last allocated block, or -1
  886.      * Set block to be ahead of the startingBlockOffset,
  887.      * and set the bitmapPtr to the corresponding spot in the bitmap.
  888.      */
  889.     if (startingBlockOffset >= 0) {
  890.         startingBlockOffset += 1;
  891.         block = startingBlockOffset + ofs_AllocGap;
  892.     } else {
  893.         block = 0;
  894.         startingBlockOffset = blocksPerCylinder;
  895.     }
  896.     bitmapPtr = 
  897.         &(ofsPtr->dataBlockBitmap[cylinderNum * ofsPtr->bytesPerCylinder
  898.                      + block / 2]);
  899.      /*
  900.      * Walk through the bitmap.  We are guaranteed from SelectCylinder that
  901.      * there is a free block in this cylinder.
  902.      * Each byte in the bitmap covers two 4K blocks.
  903.      * The 'UpperBlock' covered by the byte is an even numbered block,
  904.      * and the 'LowerBlock' is odd.
  905.      */
  906.     for ( ; block != startingBlockOffset; block++) {
  907.         fs_Stats.alloc.cylBitmapSearches++;
  908.         if (block >= blocksPerCylinder) {
  909.          /*
  910.           * Wrap back to the beginning of the cylinder
  911.           */
  912.          block -= blocksPerCylinder;
  913.          bitmapPtr -= ofsPtr->bytesPerCylinder;
  914.         }
  915.         if ((block & 0x1) == 0 && UpperBlockFree(*bitmapPtr)) {
  916.         mask = 0xf0;
  917.         goto haveFreeBlock;
  918.         }
  919.         if ((block & 0x1) != 0 && LowerBlockFree(*bitmapPtr)) {
  920.         mask = 0x0f;
  921.         goto haveFreeBlock;
  922.         }
  923.         if (block & 0x1) {
  924.         bitmapPtr++;
  925.         }
  926.     }
  927.     UNLOCK_MONITOR;
  928.     panic("FindBlockInt: no block\n");
  929.     *blockNumPtr = -1;
  930.     ofs_AllocGap = CONTIGUOUS;
  931.     LOCK_MONITOR;
  932.     return;
  933.  
  934. haveFreeBlock:
  935.     blockNum = cylinderNum * blocksPerCylinder + block;
  936.     }
  937.     if (allocate) {
  938.     if (*bitmapPtr & mask) {
  939.         printf("bitmap = <%x>, checkMask = <%x>\n",
  940.                    *bitmapPtr & 0xff, mask & 0xff);
  941.         printf("FsFindBlockInt, error in {Upper/Lower}BlockFree, failing.\n");
  942.         *blockNumPtr = -1;
  943.         return;
  944.     }
  945.     *bitmapPtr |= mask;
  946.     }
  947.  
  948.     *bitmapPtrPtr = bitmapPtr;
  949.     *blockNumPtr = blockNum;
  950.     fs_Stats.alloc.blocksAllocated++;
  951. }
  952.  
  953.  
  954. /*
  955.  *----------------------------------------------------------------------
  956.  *
  957.  * OfsBlockFind --
  958.  *
  959.  *    Search the bit map starting at the given cylinder for a free block.
  960.  *
  961.  * Results:
  962.  *    Results from FindBlockInt.
  963.  *
  964.  * Side effects:
  965.  *    None.
  966.  *
  967.  *----------------------------------------------------------------------
  968.  */
  969. ENTRY void
  970. OfsBlockFind(hashSeed, ofsPtr, nearBlock, allocate, blockNumPtr, bitmapPtrPtr)
  971.     int            hashSeed;    /* Seed for cylinder hash. */
  972.     Ofs_Domain     *ofsPtr;     /* Domain to allocate blocks in . */
  973.     int            nearBlock;      /* Block number where this block should
  974.                      * be near. */
  975.     Boolean        allocate;       /* TRUE if allocating full block, FALSE
  976.                      * if intend to fragment block. */
  977.     int            *blockNumPtr;      /* Block number that was found. */
  978.     unsigned char    **bitmapPtrPtr;    /* Bit map entry that corresponds to
  979.                      * the block. */
  980. {
  981.     LOCK_MONITOR;
  982.  
  983.     if (ofsPtr->summaryInfoPtr->numFreeKbytes - FS_FRAGMENTS_PER_BLOCK <
  984.         ofsPtr->minKFree) {
  985.     *blockNumPtr = -1;
  986.     UNLOCK_MONITOR;
  987.     return;
  988.     }
  989.  
  990.     FindBlockInt(hashSeed, ofsPtr, nearBlock, allocate, blockNumPtr, 
  991.          bitmapPtrPtr);
  992.     if (*blockNumPtr != -1) {
  993.     ofsPtr->summaryInfoPtr->numFreeKbytes -= FS_FRAGMENTS_PER_BLOCK;
  994.     }
  995.  
  996.     UNLOCK_MONITOR;
  997. }
  998.  
  999.  
  1000. /*
  1001.  *----------------------------------------------------------------------
  1002.  *
  1003.  * OfsBlockFree --
  1004.  *
  1005.  *    Put the given block back into the bit map.
  1006.  *
  1007.  * Results:
  1008.  *    None.
  1009.  *
  1010.  * Side effects:
  1011.  *    The bit map is modified.
  1012.  *
  1013.  *----------------------------------------------------------------------
  1014.  */
  1015.  
  1016. ENTRY void
  1017. OfsBlockFree(ofsPtr, blockNum)
  1018.     register Ofs_Domain *ofsPtr;     /* Handle for file to alloc blocks 
  1019.                      * for. */
  1020.     int              blockNum;       /* Block number to free. */
  1021. {
  1022.     register unsigned char *bitmapPtr;
  1023.     int               cylinderNum;
  1024.     register int       mask;
  1025.     register int       checkMask;
  1026.  
  1027.     LOCK_MONITOR;
  1028.  
  1029.     ofsPtr->summaryInfoPtr->numFreeKbytes += FS_FRAGMENTS_PER_BLOCK;
  1030.     fs_Stats.alloc.blocksFreed++;
  1031.     bitmapPtr = GetBitmapPtr(ofsPtr, blockNum);
  1032.     cylinderNum = (unsigned int) blockNum / 
  1033.             ofsPtr->headerPtr->geometry.blocksPerCylinder;
  1034.     ofsPtr->cylinders[cylinderNum].blocksFree++;
  1035.     if ((blockNum % ofsPtr->headerPtr->geometry.blocksPerCylinder) & 0x1) {
  1036.     mask = 0xf0;
  1037.     } else {
  1038.     mask = 0x0f;
  1039.     }
  1040.     checkMask = ~mask & 0xff;
  1041.     if ((*bitmapPtr & checkMask) != checkMask) {
  1042.     printf("bitmap = <%x>, checkMask = <%x>\n",
  1043.                *bitmapPtr & 0xff, checkMask & 0xff);
  1044.         UNLOCK_MONITOR;
  1045.     printf("OfsBlockFree free block %d\n", blockNum);
  1046.     return;
  1047.     } else {
  1048.     *bitmapPtr &= mask;
  1049.     }
  1050.  
  1051.     UNLOCK_MONITOR;
  1052. }
  1053.  
  1054.  
  1055. /*
  1056.  *----------------------------------------------------------------------
  1057.  *
  1058.  * OfsFragFind --
  1059.  *
  1060.  *    Allocate a fragment out of the bit map.  If possible the fragment
  1061.  *    is allocated where the last fragment was allocated.
  1062.  *
  1063.  * Results:
  1064.  *    A logical block number and offset into the block where the
  1065.  *    fragment begins.
  1066.  *
  1067.  * Side effects:
  1068.  *    The bit map and the fragment lists might be modified.
  1069.  *
  1070.  *----------------------------------------------------------------------
  1071.  */
  1072.  
  1073. ENTRY void
  1074. OfsFragFind(hashSeed, ofsPtr, numFrags, lastFragBlock, lastFragOffset, 
  1075.         lastFragSize, newFragBlockPtr, newFragOffsetPtr)
  1076.     int            hashSeed;        /* Seed for cylinder hash. */
  1077.     register Ofs_Domain *ofsPtr;        /* Domain out of which to 
  1078.                          * allocate the fragment. */
  1079.     int                  numFrags;           /* Number of fragments to get: 
  1080.                          * 1, 2, or 3 */
  1081.     int                  lastFragBlock;        /* Block number where the last 
  1082.                          * fragment for this file was 
  1083.                          * allocated. */
  1084.     int                  lastFragOffset;        /* Fragment offset in the 
  1085.                          * block. */
  1086.     int                  lastFragSize;        /* Number of fragments in the 
  1087.                          * last fragment. */
  1088.     int                  *newFragBlockPtr;    /* Where to return new fragment
  1089.                              * block number. */
  1090.     int                  *newFragOffsetPtr;    /* Where to return new fragment
  1091.                          * offset. */
  1092. {
  1093.     register OfsFragment          *fragPtr;
  1094.     register unsigned char     *bitmapPtr = (unsigned char *) NIL;
  1095.     register int           *savedOffsets;
  1096.     unsigned char        savedBitmap;
  1097.     int                   *fragOffsetPtr;
  1098.     int                   fragOffset = 0;
  1099.     int                   fragBlock;
  1100.     unsigned char            *tBitmapPtr;
  1101.     List_Links                  *fragList;
  1102.     int                   byteOffset;
  1103.     int                   fragMask = 0;
  1104.     int                   i;
  1105.     int                   blockNum = -1;
  1106.     int                fragsToAllocate;
  1107.  
  1108.     LOCK_MONITOR;
  1109.  
  1110.     if (lastFragBlock == -1)  {
  1111.     fragsToAllocate = numFrags;
  1112.     } else {
  1113.     fragsToAllocate = numFrags - lastFragSize;
  1114.     }
  1115.     if (ofsPtr->summaryInfoPtr->numFreeKbytes - fragsToAllocate <
  1116.         ofsPtr->minKFree) {
  1117.     *newFragBlockPtr = -1;
  1118.     UNLOCK_MONITOR;
  1119.     return;
  1120.     }
  1121.  
  1122.     /*
  1123.      * First try the block where the last fragment was.
  1124.      */
  1125.  
  1126.     fs_Stats.alloc.fragsAllocated++;
  1127.     if (lastFragBlock != -1 && 
  1128.     lastFragOffset + numFrags <= FS_FRAGMENTS_PER_BLOCK ) {
  1129.     fs_Stats.alloc.fragUpgrades++;
  1130.     bitmapPtr = GetBitmapPtr(ofsPtr, lastFragBlock);
  1131.     if ((lastFragBlock % ofsPtr->headerPtr->geometry.blocksPerCylinder)
  1132.         & 0x1) {
  1133.         byteOffset = lastFragOffset + 4;
  1134.     } else {
  1135.         byteOffset = lastFragOffset;
  1136.     }
  1137.     fragMask = 0;
  1138.     blockNum = lastFragBlock;
  1139.     fragOffset = lastFragOffset;
  1140.     /*
  1141.      * Now make sure that there are enough free fragments in the block. 
  1142.      */
  1143.     for (i = byteOffset + lastFragSize; i < byteOffset + numFrags; i++) {
  1144.         if (*bitmapPtr & bitMasks[i]) {
  1145.         blockNum = -1;
  1146.         break;
  1147.         }
  1148.         fragMask |= bitMasks[i];
  1149.     }
  1150.     }
  1151.  
  1152.     if (blockNum == -1) {
  1153.     /* 
  1154.      * We couldn't find space in the block where the last fragment was.
  1155.      * First try all fragment lists starting with the one of the 
  1156.      * desired size.
  1157.      */
  1158.  
  1159.     for (i = numFrags - 1; 
  1160.          i < OFS_NUM_FRAG_SIZES && blockNum == -1; 
  1161.          i++) {
  1162.         fragList = ofsPtr->fragLists[i];
  1163.         while (!List_IsEmpty(fragList)) {
  1164.         fragPtr = (OfsFragment *) List_First(fragList);
  1165.         List_Remove((List_Links *) fragPtr);
  1166.         fragBlock = fragPtr->blockNum;
  1167.         free((Address) fragPtr);
  1168.         /*
  1169.          * Check to make sure that there really is a fragment of the
  1170.          * needed size in the block.  These fragment lists are hints.
  1171.          */
  1172.         bitmapPtr = GetBitmapPtr(ofsPtr, fragBlock);
  1173.         if ((fragBlock %
  1174.              ofsPtr->headerPtr->geometry.blocksPerCylinder) & 0x1) {
  1175.             fragOffset = fragTable[GetLowerFragMask(*bitmapPtr)][i];
  1176.         } else {
  1177.             fragOffset = fragTable[GetUpperFragMask(*bitmapPtr)][i];
  1178.         }
  1179.         if (fragOffset != -1) {
  1180.             /*
  1181.              * There is a fragment of this size so use this block.
  1182.              */
  1183.             blockNum = fragBlock;
  1184.             break;
  1185.         } else {
  1186.             fs_Stats.alloc.badFragList++;
  1187.         }
  1188.         }
  1189.     }
  1190.  
  1191.     if (blockNum == -1) {
  1192.         fs_Stats.alloc.fullBlockFrags++;
  1193.         /*
  1194.          * We couldn't find a fragmented block to use so have to 
  1195.          * fragment a full block.
  1196.          */
  1197.         FindBlockInt(hashSeed, ofsPtr, -1, FALSE, &blockNum, 
  1198.              &tBitmapPtr);
  1199.         if (blockNum == -1) {
  1200.         *newFragBlockPtr = -1;
  1201.         UNLOCK_MONITOR;
  1202.         return;
  1203.         }
  1204.         bitmapPtr = tBitmapPtr;
  1205.         fragOffset = 0;
  1206.     }
  1207.     /*
  1208.      * See if the block number corresponds to the high or low
  1209.      * end of the bitmap byte.  If, for example, there are an odd
  1210.      * number of blocks per cylinder, an even block number may be
  1211.      * odd relative to the start of the cylinder, and relative to
  1212.      * the start of the bitmap for that cylinder.
  1213.      */
  1214.     if ((blockNum % ofsPtr->headerPtr->geometry.blocksPerCylinder)
  1215.         & 0x1) {
  1216.         byteOffset = fragOffset + 4;
  1217.     } else {
  1218.         byteOffset = fragOffset;
  1219.     }
  1220.     fragMask = 0;
  1221.     for (i = byteOffset; i < byteOffset + numFrags; i++) {
  1222.         fragMask |= bitMasks[i];
  1223.     }
  1224.     ofsPtr->summaryInfoPtr->numFreeKbytes -= numFrags;
  1225.     } else {
  1226.     ofsPtr->summaryInfoPtr->numFreeKbytes -= numFrags - lastFragSize;
  1227.     fs_Stats.alloc.fragsUpgraded++;
  1228.     }
  1229.  
  1230.     /*
  1231.      * Now put the block on all appropriate fragment lists.  savedOffsets 
  1232.      * points to the fragment offsets before we allocated the new fragment out
  1233.      * of the block.  fragOffsetPtr points to the fragment offset after
  1234.      * we allocated the fragment out of the block.
  1235.      */
  1236.  
  1237.     if (*bitmapPtr & fragMask) {
  1238.     UNLOCK_MONITOR;
  1239.     panic("Find frag bitmap error\n");
  1240.     *newFragBlockPtr = -1;
  1241.     return;
  1242.     } else {
  1243.     savedBitmap = *bitmapPtr;
  1244.     *bitmapPtr |= fragMask;
  1245.     }
  1246.     if ((blockNum % ofsPtr->headerPtr->geometry.blocksPerCylinder) & 0x1) {
  1247.     savedOffsets = fragTable[GetLowerFragMask(savedBitmap)];
  1248.     fragOffsetPtr = fragTable[GetLowerFragMask(*bitmapPtr)];
  1249.     } else {
  1250.     savedOffsets = fragTable[GetUpperFragMask(savedBitmap)];
  1251.     fragOffsetPtr = fragTable[GetUpperFragMask(*bitmapPtr)];
  1252.     }
  1253.     for (i = 0; i < OFS_NUM_FRAG_SIZES; i++, savedOffsets++, fragOffsetPtr++) {
  1254.     if (*savedOffsets == -1 && *fragOffsetPtr != -1) {
  1255.         /*
  1256.          * The block was not on the fragment list of this size before we
  1257.          * allocated a new fragment out of it, so put it there. 
  1258.          */
  1259.         fragPtr = (OfsFragment *) malloc(sizeof(OfsFragment));
  1260.         List_Insert((List_Links *) fragPtr, 
  1261.             LIST_ATREAR(ofsPtr->fragLists[i]));
  1262.         fragPtr->blockNum = blockNum;
  1263.     }
  1264.     }
  1265.  
  1266.     *newFragBlockPtr = blockNum;
  1267.     *newFragOffsetPtr = fragOffset;
  1268.  
  1269.     if (fragOffset + numFrags > FS_FRAGMENTS_PER_BLOCK) {
  1270.     UNLOCK_MONITOR;
  1271.     panic("FsdmFragFind, fragment overrun, offset %d numFrags %d\n",
  1272.             fragOffset, numFrags);
  1273.     return;
  1274.     }
  1275.  
  1276.     UNLOCK_MONITOR;
  1277. }
  1278.  
  1279.  
  1280. /*
  1281.  *----------------------------------------------------------------------
  1282.  *
  1283.  * OfsFragFree --
  1284.  *
  1285.  *    Free the given fragment.
  1286.  *
  1287.  * Results:
  1288.  *    None.
  1289.  *
  1290.  * Side effects:
  1291.  *    The bit map and fragment lists are modified.
  1292.  *
  1293.  *----------------------------------------------------------------------
  1294.  */
  1295.  
  1296. ENTRY void
  1297. OfsFragFree(ofsPtr, numFrags, fragBlock, fragOffset) 
  1298.     register Ofs_Domain *ofsPtr;    /* Domain out of which to allocate the
  1299.                        fragment. */
  1300.     int              numFrags;     /* Number of fragments to free: 1, 2,
  1301.                        or 3 */
  1302.     int              fragBlock;    /* Block number where the fragment
  1303.                        was allocated. */
  1304.     int              fragOffset;    /* Fragment offset in the block. */
  1305. {
  1306.     register int       *fragOffsets;
  1307.     register int        *savedOffsets;
  1308.     register unsigned char *bitmapPtr;
  1309.     OfsFragment           *fragPtr;
  1310.     unsigned char         mask;
  1311.     int                    i;
  1312.     int                    byteOffset;
  1313.     int                fragMask;
  1314.  
  1315.     LOCK_MONITOR;
  1316.  
  1317.     fs_Stats.alloc.fragsFreed++;
  1318.  
  1319.     ofsPtr->summaryInfoPtr->numFreeKbytes += numFrags;
  1320.  
  1321.     bitmapPtr = GetBitmapPtr(ofsPtr, fragBlock);
  1322.  
  1323.     /*
  1324.      * Determine whether should clear upper or lower 4 bits.
  1325.      */
  1326.  
  1327.     if ((fragBlock % ofsPtr->headerPtr->geometry.blocksPerCylinder) & 0x1) {
  1328.     byteOffset = fragOffset + 4;
  1329.     savedOffsets = fragTable[GetLowerFragMask(*bitmapPtr)];
  1330.     } else {
  1331.     byteOffset = fragOffset;
  1332.     savedOffsets = fragTable[GetUpperFragMask(*bitmapPtr)];
  1333.     }
  1334.  
  1335.     /*
  1336.      * Determine the bits to unset and unset them.
  1337.      */
  1338.  
  1339.     mask = 0;
  1340.     for (i = byteOffset; i < byteOffset + numFrags; i++) {
  1341.     mask |= bitMasks[i];
  1342.     }
  1343.     if ((*bitmapPtr & mask) != mask) {
  1344.     printf("OfsFragFree: bitmap = <%x>, checkMask = <%x>\n",
  1345.                *bitmapPtr & 0xff, mask & 0xff);
  1346.     UNLOCK_MONITOR;
  1347.     printf("OfsFragFree: block not free, block %d, numFrag %d, offset %d\n",
  1348.             fragBlock, numFrags, fragOffset);
  1349.     return;
  1350.     } else {
  1351.     *bitmapPtr &= ~mask;
  1352.     }
  1353.  
  1354.     /*
  1355.      * Determine the new state of the block and put things onto the
  1356.      * proper fragment lists.  savedOffsets points to the array of frag
  1357.      * offsets before we freed the fragment in the block and fragOffsets
  1358.      * points to the frag offsets after we freed the fragment.
  1359.      */
  1360.  
  1361.     if ((fragBlock % ofsPtr->headerPtr->geometry.blocksPerCylinder) & 0x1) {
  1362.     fragMask = GetLowerFragMask(*bitmapPtr);
  1363.     } else {
  1364.     fragMask = GetUpperFragMask(*bitmapPtr);
  1365.     }
  1366.     if (fragMask == 0) {
  1367.     fs_Stats.alloc.fragToBlock++;
  1368.     /*
  1369.      * The block has become totally free.
  1370.      */
  1371.     ofsPtr->cylinders[(unsigned int) fragBlock / 
  1372.          ofsPtr->headerPtr->geometry.blocksPerCylinder].blocksFree++;
  1373.     UNLOCK_MONITOR;
  1374.     return;
  1375.     }
  1376.     fragOffsets = fragTable[fragMask];
  1377.     for (i = 0; i < OFS_NUM_FRAG_SIZES; i++, fragOffsets++, savedOffsets++) {
  1378.     if (*savedOffsets == -1 && *fragOffsets != -1) {
  1379.         /*
  1380.          * A fragment of this size did not exist before we freed the 
  1381.          * fragment but it does exist now.
  1382.          */
  1383.         fragPtr = (OfsFragment *) malloc(sizeof(OfsFragment));
  1384.         List_Insert((List_Links *) fragPtr, 
  1385.                 LIST_ATREAR(ofsPtr->fragLists[i]));
  1386.         fragPtr->blockNum = fragBlock;
  1387.     }
  1388.     }
  1389.  
  1390.     UNLOCK_MONITOR;
  1391. }
  1392.  
  1393.  
  1394. /*
  1395.  *----------------------------------------------------------------------
  1396.  *
  1397.  * OnlyFrag --
  1398.  *
  1399.  *    Determine if the given fragment is the only one in the block.
  1400.  *
  1401.  * Results:
  1402.  *    TRUE if the given fragment is the only one in the block.
  1403.  *
  1404.  * Side effects:
  1405.  *    The rest of the block is marked as allocated if the given fragment
  1406.  *    is the only one in the block.
  1407.  *
  1408.  *----------------------------------------------------------------------
  1409.  */
  1410.  
  1411. ENTRY Boolean
  1412. OnlyFrag(ofsPtr, numFrags, fragBlock, fragOffset) 
  1413.     register Ofs_Domain *ofsPtr;    /* Domain of fragment. */
  1414.     int              numFrags;     /* Number of fragments to free: 1, 2,
  1415.                        or 3 */
  1416.     int              fragBlock;    /* Block number where the fragment
  1417.                        was allocated. */
  1418.     int              fragOffset;    /* Fragment offset in the block. */
  1419. {
  1420.     register unsigned char    *bitmapPtr;
  1421.     unsigned char          mask;
  1422.     int                        i;
  1423.     int                        byteOffset;
  1424.     int                blockMask;
  1425.  
  1426.     LOCK_MONITOR;
  1427.  
  1428.     bitmapPtr = GetBitmapPtr(ofsPtr, fragBlock);
  1429.  
  1430.     /*
  1431.      * Determine whether should access upper or lower 4 bits.
  1432.      */
  1433.     if ((fragBlock % ofsPtr->headerPtr->geometry.blocksPerCylinder) & 0x1) {
  1434.     byteOffset = fragOffset + 4;
  1435.     blockMask = 0x0f;
  1436.     } else {
  1437.     byteOffset = fragOffset;
  1438.     blockMask = 0xf0;
  1439.     }
  1440.  
  1441.     /*
  1442.      * Determine which bits are set for this fragment.
  1443.      */
  1444.     mask = 0;
  1445.     for (i = byteOffset; i < byteOffset + numFrags; i++) {
  1446.     mask |= bitMasks[i];
  1447.     }
  1448.     if ((*bitmapPtr & mask) != mask) {
  1449.     printf("bitmap = <%x>, checkMask = <%x>\n",
  1450.                *bitmapPtr & 0xff, mask & 0xff);
  1451.     UNLOCK_MONITOR;
  1452.     panic("OnlyFrag: Frag block corrupted.\n");
  1453.     return(FALSE);
  1454.     }
  1455.     if (((*bitmapPtr & ~mask) & blockMask) != 0) {
  1456.     /*
  1457.      * There is another fragment in this block so we can't put the block
  1458.      * into the bad block file yet.
  1459.      */
  1460.     UNLOCK_MONITOR;
  1461.     return(FALSE);
  1462.     }
  1463.  
  1464.     /*
  1465.      * We were the only fragment in this block.  Mark the rest of the block
  1466.      * as allocated because our caller is going to put this block into the
  1467.      * bad block file.
  1468.      */
  1469.     *bitmapPtr |= blockMask;
  1470.     ofsPtr->summaryInfoPtr->numFreeKbytes -= 
  1471.                     FS_FRAGMENTS_PER_BLOCK - numFrags;
  1472.  
  1473.     UNLOCK_MONITOR;
  1474.     return(TRUE);
  1475. }
  1476.  
  1477. /*
  1478.  *----------------------------------------------------------------------
  1479.  *
  1480.  * UpgradeFragment --
  1481.  *
  1482.  *    Take a fragment and make it of sufficient size to fit the new
  1483.  *    fragment size.
  1484.  *
  1485.  * Results:
  1486.  *    SUCCESS, FS_NO_DISK_SPACE, or FS_WOULD_BLOCK (if cache is full).
  1487.  *
  1488.  * Side effects:
  1489.  *    *indexInfoPtr may be modified along with *indexInfoPtr->blockAddrPtr.
  1490.  *
  1491.  *----------------------------------------------------------------------
  1492.  */
  1493.  
  1494. static ReturnStatus
  1495. UpgradeFragment(ofsPtr, handlePtr, indexInfoPtr, curLastBlock, newLastFrag, 
  1496.         dontWriteThru, dontBlock, dirtiedIndexPtr)
  1497.     Ofs_Domain        *ofsPtr;        /* Domain of file. */
  1498.     Fsio_FileIOHandle        *handlePtr;    /* File to allocate blocks 
  1499.                          * for. */
  1500.     register OfsBlockIndexInfo *indexInfoPtr;    /* Index info structure. */
  1501.     int            curLastBlock;        /* The current last block. */
  1502.     int            newLastFrag;        /* New last fragment for this
  1503.                          * file.  Fragments are numbered
  1504.                          * from 0. */
  1505.     Boolean        dontWriteThru;        /* TRUE => make sure that the
  1506.                          * cache block that contains
  1507.                          * upgraded block isn't forced
  1508.                          * through to disk. */
  1509.     int            dontBlock;        /* FSCACHE_DONT_BLOCK */
  1510.     Boolean        *dirtiedIndexPtr;     /* TRUE if modified the block 
  1511.                          * pointer in the file index 
  1512.                          * structure. */
  1513. {
  1514.     register    Fsdm_FileDescriptor *descPtr;
  1515.     register    int          blockAddr;
  1516.     int                 curLastFrag;    /* Current last fragment for
  1517.                          * this file. */
  1518.     int                 curFragBlock;    /* Current disk block used for 
  1519.                          * last block in file. */
  1520.     int                 curFragOffset;    /* Offset in the block where
  1521.                          * the fragment begins. */
  1522.     int                 newFragBlock;    /* New disk block used for last
  1523.                            block in file. */
  1524.     int                 newFragOffset;    /* Offset in new block where 
  1525.                          * the fragment begins. */
  1526.     unsigned char          *bitmapPtr;
  1527.     Fscache_Block         *fragCacheBlockPtr;
  1528.     Boolean             found;
  1529.     ReturnStatus         status = SUCCESS;
  1530.     int                 flags;
  1531. #ifdef SOSP91
  1532.     Boolean        isForeign = FALSE;    /* Due to migration? */
  1533. #endif SOSP91
  1534.  
  1535.     descPtr = handlePtr->descPtr;
  1536.     blockAddr = *(indexInfoPtr->blockAddrPtr);
  1537.  
  1538.     curLastFrag = (unsigned int) (descPtr->lastByte & FS_BLOCK_OFFSET_MASK) /
  1539.                     FS_FRAGMENT_SIZE;
  1540.  
  1541.     if (curLastBlock >= FSDM_NUM_DIRECT_BLOCKS || curLastFrag == LAST_FRAG ||
  1542.     curLastFrag >= newLastFrag) {
  1543.     /*
  1544.      * There is already enough space so return.
  1545.      */
  1546.     goto exit;
  1547.     }
  1548. #ifdef SOSP91
  1549.     if (proc_RunningProcesses[0] != (Proc_ControlBlock *) NIL) {
  1550.     if ((proc_RunningProcesses[0]->state == PROC_MIGRATED) ||
  1551.         (proc_RunningProcesses[0]->genFlags &
  1552.         (PROC_FOREIGN | PROC_MIGRATING))) {
  1553.         isForeign = TRUE;
  1554.     }
  1555.     }
  1556. #endif SOSP91
  1557.  
  1558.     curFragBlock = (unsigned int) blockAddr / FS_FRAGMENTS_PER_BLOCK;
  1559.     curFragOffset = blockAddr & FRAG_OFFSET_MASK;
  1560.     if (newLastFrag < LAST_FRAG) {
  1561.     /*
  1562.      * Have to allocate a larger fragment.  Note that fragments are
  1563.      * numbered from zero so that the fragment number + 1 is equal to the
  1564.      * number of fragments in the block.
  1565.      */
  1566.     OfsFragFind(handlePtr->hdr.fileID.minor, ofsPtr, newLastFrag + 1, 
  1567.             curFragBlock, curFragOffset, curLastFrag + 1,
  1568.             &newFragBlock, &newFragOffset);
  1569.     if (newFragBlock == -1) {
  1570.         status = FS_NO_DISK_SPACE;
  1571.         goto exit;
  1572.     }
  1573.     if (curFragBlock == newFragBlock && curFragOffset == newFragOffset) {
  1574.         /*
  1575.          * Were able to extend the old fragment so return.
  1576.          */
  1577.         descPtr->numKbytes += newLastFrag - curLastFrag;
  1578.         goto exit;
  1579.     }
  1580.     } else {
  1581.     /*
  1582.      * Allocate a full block.
  1583.      */
  1584.     OfsBlockFind(handlePtr->hdr.fileID.minor, ofsPtr,
  1585.             indexInfoPtr->lastDiskBlock,
  1586.             TRUE, &newFragBlock, &bitmapPtr);
  1587.     if (newFragBlock == -1) {
  1588.         status = FS_NO_DISK_SPACE;
  1589.         goto exit;
  1590.     } else if (newFragBlock == 0 && handlePtr->hdr.fileID.minor != 2) {
  1591.         printf("UpgradeFragment: tried to allocate block 0 to non-root file #%d\n",
  1592.             handlePtr->hdr.fileID.minor);
  1593.         status = FAILURE;
  1594.         goto exit;
  1595.     }
  1596.     newFragOffset = 0;
  1597.     }
  1598.         
  1599.     /*
  1600.      * Copy over the old fragment into the new larger one.  This
  1601.      * is done by fetching the block into the cache, switching the value in 
  1602.      * the file descriptor and marking the block dirty.
  1603.      */
  1604.     Fscache_FetchBlock(&handlePtr->cacheInfo, 
  1605.               curLastBlock, FSCACHE_DATA_BLOCK | dontBlock,
  1606.               &fragCacheBlockPtr, &found);
  1607.     if (fragCacheBlockPtr == (Fscache_Block *)NIL) {
  1608.     status = FS_WOULD_BLOCK;
  1609.     goto exit;
  1610.     }
  1611.     fs_Stats.blockCache.fragAccesses++;
  1612. #ifdef SOSP91
  1613.     if (isForeign) {
  1614.     fs_SospMigStats.blockCache.fragAccesses++;
  1615.     }
  1616. #endif SOSP91
  1617.     if (!found) {
  1618.     status = OfsDeviceBlockIO(ofsPtr, FS_READ, 
  1619.            blockAddr +
  1620.            ofsPtr->headerPtr->dataOffset * FS_FRAGMENTS_PER_BLOCK,
  1621.            curLastFrag + 1, fragCacheBlockPtr->blockAddr);
  1622.     if (status != SUCCESS) {
  1623.         Fscache_UnlockBlock(fragCacheBlockPtr, 0, -1, 0, 0);
  1624.         OfsFragFree(ofsPtr, newLastFrag + 1, 
  1625.                newFragBlock, newFragOffset);
  1626.         goto exit;
  1627.     }
  1628.     fs_Stats.blockCache.fragZeroFills++;
  1629.     /*
  1630.      * Zero fill the rest of the block.
  1631.      */
  1632.     bzero(fragCacheBlockPtr->blockAddr +
  1633.             (curLastFrag + 1) * FS_FRAGMENT_SIZE,
  1634.         FS_BLOCK_SIZE - (curLastFrag + 1) * FS_FRAGMENT_SIZE);
  1635.     } else {
  1636.     fs_Stats.blockCache.fragHits++;
  1637. #ifdef SOSP91
  1638.     if (isForeign) {
  1639.         fs_SospMigStats.blockCache.fragHits++;
  1640.     }
  1641. #endif SOSP91
  1642.     if (fragCacheBlockPtr->flags & FSCACHE_READ_AHEAD_BLOCK) {
  1643.         fs_Stats.blockCache.readAheadHits++;
  1644. #ifdef SOSP91
  1645.     if (isForeign) {
  1646.         fs_SospMigStats.blockCache.readAheadHits++;
  1647.     }
  1648. #endif SOSP91
  1649.     }
  1650.     }
  1651.     /*
  1652.      * Commit the change in the fragments location.
  1653.      * 1 - unlock the cache block, specifying the new location.
  1654.      *        This step blocks if I/O is in progress on the block.
  1655.      *        After any I/O (such as a writeback) completes, then
  1656.      *        the block will be put on the dirty list with the new address.
  1657.      * 2 - update the file descriptors indexing information to point to
  1658.      *        the new block.
  1659.      * 3 - free up the old fragment.
  1660.      *
  1661.      * (As a historical note, steps 1 & 2 used to be reversed.  Files
  1662.      *    were ending up with the wrong trailing fragment occasionally.)
  1663.      */
  1664.  
  1665.     if (dontWriteThru) {
  1666.     flags = FSCACHE_CLEAR_READ_AHEAD | FSCACHE_DONT_WRITE_THRU;
  1667.     } else {
  1668.     flags = FSCACHE_CLEAR_READ_AHEAD;
  1669.     }
  1670.     blockAddr = newFragBlock * FS_FRAGMENTS_PER_BLOCK + newFragOffset;
  1671.     Fscache_UnlockBlock(fragCacheBlockPtr, (unsigned) Fsutil_TimeInSeconds(), 
  1672.                blockAddr, 
  1673.                (newLastFrag + 1) * FS_FRAGMENT_SIZE, flags);
  1674.  
  1675.     *(indexInfoPtr->blockAddrPtr) = blockAddr;
  1676.     descPtr->numKbytes += newLastFrag - curLastFrag;
  1677.     descPtr->flags |= FSDM_FD_SIZE_DIRTY;
  1678.     *dirtiedIndexPtr = TRUE;
  1679.  
  1680.     OfsFragFree(ofsPtr, curLastFrag + 1, curFragBlock, curFragOffset);
  1681.  
  1682. exit:
  1683.     return(status);
  1684. }
  1685.  
  1686.  
  1687. /*
  1688.  *----------------------------------------------------------------------
  1689.  *
  1690.  * AllocateBlock --
  1691.  *
  1692.  *    Allocate a block for the file.
  1693.  *
  1694.  * Results:
  1695.  *    FS_NO_DISK_SPACE if could not allocate block.  Otherwise,
  1696.  *    returns SUCCESS.
  1697.  *
  1698.  * Side effects:
  1699.  *     Also *indexInfoPtr may be modified along with *indexInfoPtr->blockAddr.
  1700.  *
  1701.  *----------------------------------------------------------------------
  1702.  */
  1703.  
  1704. static ReturnStatus
  1705. AllocateBlock(handlePtr, descPtr, indexInfoPtr, newLastByte, curLastBlock, 
  1706.           dontBlock, dirtiedIndexPtr)
  1707.     Fsio_FileIOHandle        *handlePtr;    /* File to allocate block for.*/
  1708.     register Fsdm_FileDescriptor     *descPtr;    /* Pointer to the file desc. */
  1709.     register OfsBlockIndexInfo     *indexInfoPtr;     /* Index info structure. */
  1710.     int                newLastByte;    /* The new last byte in the 
  1711.                          * file. */
  1712.     int                curLastBlock;    /* The last block in the file 
  1713.                          * before started allocating. */
  1714.     int                dontBlock;    /* FSCACHE_DONT_BLOCK */
  1715.     Boolean            *dirtiedIndexPtr;/* TRUE if a new block was 
  1716.                           * allocated. */
  1717. {
  1718.     register    int         blockAddr;
  1719.     register    Ofs_Domain     *ofsPtr;
  1720.     unsigned char          *bitmapPtr;
  1721.     int                 newFragIndex;    /* {0, 1, 2, 3} */
  1722.     int                 blockNum;    /* Disk block that is 
  1723.                          * allocated. */
  1724.     int                 newFragOffset;    /* Offset in disk block where
  1725.                          * fragment begins. */
  1726.     ReturnStatus         status = SUCCESS;
  1727.  
  1728.     ofsPtr = indexInfoPtr->ofsPtr;
  1729.     blockAddr = *(indexInfoPtr->blockAddrPtr);
  1730.     if (blockAddr == 0 && handlePtr->hdr.fileID.minor != 2) {
  1731.     /*
  1732.      * The zero'th block belongs to the root directory which is
  1733.      * created by the makeFilesystem program.
  1734.      */
  1735.     printf("AllocateBlock: non-root file <%d,%d> with block 0\n",
  1736.             handlePtr->hdr.fileID.major, handlePtr->hdr.fileID.minor);
  1737.     return(FAILURE);
  1738.     }
  1739.  
  1740.     if (indexInfoPtr->blockNum >= FSDM_NUM_DIRECT_BLOCKS ||
  1741.     indexInfoPtr->blockNum < curLastBlock) {
  1742.     newFragIndex = LAST_FRAG;
  1743.     } else {
  1744.     newFragIndex = 
  1745.      (unsigned int) (newLastByte & FS_BLOCK_OFFSET_MASK) / FS_FRAGMENT_SIZE;
  1746.     }
  1747.  
  1748.     if (descPtr->lastByte == -1 || indexInfoPtr->blockNum != curLastBlock) {
  1749.     /*
  1750.      * Empty file or we are allocating a block that is before the
  1751.      * last block in the file.
  1752.      */
  1753.     if (newFragIndex < LAST_FRAG) {
  1754.         /*
  1755.          * Fragment the last block.
  1756.          */
  1757.         OfsFragFind(handlePtr->hdr.fileID.minor, ofsPtr,
  1758.             newFragIndex + 1, -1, -1, -1,
  1759.             &blockNum, &newFragOffset);
  1760.         if (blockNum != -1) {
  1761.         *(indexInfoPtr->blockAddrPtr) = 
  1762.                 blockNum * FS_FRAGMENTS_PER_BLOCK + newFragOffset;
  1763.         *dirtiedIndexPtr = TRUE;
  1764.         descPtr->numKbytes += newFragIndex + 1;
  1765.         } else {
  1766.         status = FS_NO_DISK_SPACE;
  1767.         }
  1768.     } else {
  1769.         /*
  1770.          * Allocate a full block if one isn't there already.
  1771.          */
  1772.         if (blockAddr == FSDM_NIL_INDEX) {
  1773.         OfsBlockFind(handlePtr->hdr.fileID.minor, ofsPtr,
  1774.                 indexInfoPtr->lastDiskBlock, 
  1775.                 TRUE, &blockNum, &bitmapPtr);
  1776.         if (blockNum == -1) {
  1777.             status = FS_NO_DISK_SPACE;
  1778.         } else if (blockNum == 0 && handlePtr->hdr.fileID.minor != 2) {
  1779.             /*
  1780.              * The zero'th block belongs to the root directory which is
  1781.              * created by the makeFilesystem program.
  1782.              */
  1783.             printf("AllocateBlock: non-root file <%d,%d> wants block 0\n",
  1784.                 handlePtr->hdr.fileID.major,
  1785.                 handlePtr->hdr.fileID.minor);
  1786.             status = FAILURE;
  1787.         } else {
  1788.             *(indexInfoPtr->blockAddrPtr) = 
  1789.                         blockNum * FS_FRAGMENTS_PER_BLOCK;
  1790.             descPtr->numKbytes += FS_FRAGMENTS_PER_BLOCK;
  1791.             *dirtiedIndexPtr = TRUE;
  1792.         }
  1793.         }
  1794.     }
  1795.     } else {
  1796.     /*
  1797.      * Are allocating on top of the last block so make sure that the 
  1798.      * last fragment is large enough.
  1799.      */   
  1800.     status = UpgradeFragment(ofsPtr, handlePtr, indexInfoPtr, 
  1801.                  curLastBlock, newFragIndex, TRUE,
  1802.                  dontBlock, dirtiedIndexPtr);
  1803.     }
  1804.     return(status);
  1805. }
  1806.  
  1807.  
  1808. /*
  1809.  *----------------------------------------------------------------------
  1810.  *
  1811.  * FragToBlock --
  1812.  *
  1813.  *    Upgrade the given fragment to a block.
  1814.  *
  1815.  * Results:
  1816.  *    SUCCESS, FS_NO_DISK_SPACE, FS_WOULD_BLOCK.
  1817.  *
  1818.  * Side effects:
  1819.  *    The size in the file descriptor is updated so that it is on a block
  1820.  *    boundary.
  1821.  *
  1822.  *----------------------------------------------------------------------
  1823.  */
  1824. static ReturnStatus
  1825. FragToBlock(ofsPtr, handlePtr, blockNum, dontBlock)
  1826.     Ofs_Domain            *ofsPtr;
  1827.     register Fsio_FileIOHandle    *handlePtr;
  1828.     int                blockNum;
  1829.     int                dontBlock;    /* FSCACHE_DONT_BLOCK */
  1830. {
  1831.     register Fsdm_FileDescriptor    *descPtr;
  1832.     OfsBlockIndexInfo        indexInfo;
  1833.     ReturnStatus        status;
  1834.     Boolean            dirtiedIndex;
  1835.  
  1836.     /*
  1837.      * Set up the indexing structure.
  1838.      */
  1839.     descPtr = handlePtr->descPtr;
  1840.     if (blockNum == 0) {
  1841.     /*
  1842.      * This is the first block of the file so there is no previous
  1843.      * block.
  1844.      */
  1845.     status = OfsGetFirstIndex(ofsPtr, handlePtr, blockNum, &indexInfo,
  1846.                  OFS_ALLOC_INDIRECT_BLOCKS);
  1847.     if (status != SUCCESS) {
  1848.         return(status);
  1849.     }
  1850.     } else {
  1851.     /*
  1852.      * This is not the first block in the file, so determine the
  1853.      * previous block and then go to the first block.
  1854.      */
  1855.     status = OfsGetFirstIndex(ofsPtr, handlePtr, blockNum - 1, &indexInfo,
  1856.                  OFS_ALLOC_INDIRECT_BLOCKS);
  1857.     if (status != SUCCESS) {
  1858.         return(status);
  1859.     }
  1860.     status = OfsGetNextIndex(handlePtr, &indexInfo, FALSE);
  1861.     if (status != SUCCESS) {
  1862.         OfsEndIndex(handlePtr, &indexInfo, FALSE);
  1863.         return(status);
  1864.     }
  1865.     }
  1866.  
  1867.     /*
  1868.      * Now upgrade to a full block.
  1869.      */
  1870.  
  1871.     status = UpgradeFragment(ofsPtr, handlePtr, &indexInfo, blockNum, LAST_FRAG,
  1872.                  FALSE, dontBlock, &dirtiedIndex);
  1873.     if (status == SUCCESS) {
  1874.     descPtr->lastByte = blockNum * FS_BLOCK_SIZE + FS_BLOCK_SIZE - 1;
  1875.     descPtr->descModifyTime = Fsutil_TimeInSeconds();
  1876.     descPtr->flags |= FSDM_FD_SIZE_DIRTY;
  1877.     }
  1878.     OfsEndIndex(handlePtr, &indexInfo, dirtiedIndex);
  1879.     return(status);
  1880. }
  1881.  
  1882.  
  1883.  
  1884. /*
  1885.  *----------------------------------------------------------------------
  1886.  *
  1887.  * Ofs_DomainInfo --
  1888.  *
  1889.  *    Return info about the given domain.
  1890.  *
  1891.  * Results:
  1892.  *    Error  if can't get to the domain.
  1893.  *
  1894.  * Side effects:
  1895.  *    The domain info struct is filled in.
  1896.  *
  1897.  *----------------------------------------------------------------------
  1898.  */
  1899. ReturnStatus
  1900. Ofs_DomainInfo(domainPtr, domainInfoPtr)
  1901.     Fsdm_Domain    *domainPtr;
  1902.     Fs_DomainInfo    *domainInfoPtr;
  1903. {
  1904.     Ofs_Domain    *ofsPtr = OFS_PTR_FROM_DOMAIN(domainPtr);
  1905.  
  1906.     domainInfoPtr->maxKbytes = 
  1907.             ofsPtr->headerPtr->dataBlocks * FS_FRAGMENTS_PER_BLOCK;
  1908.     domainInfoPtr->freeKbytes = ofsPtr->summaryInfoPtr->numFreeKbytes;
  1909.     domainInfoPtr->maxFileDesc = ofsPtr->headerPtr->numFileDesc;
  1910.     domainInfoPtr->freeFileDesc = ofsPtr->summaryInfoPtr->numFreeFileDesc;
  1911.     domainInfoPtr->blockSize = FS_BLOCK_SIZE;
  1912.     domainInfoPtr->optSize = FS_BLOCK_SIZE;
  1913.  
  1914.     return(SUCCESS);
  1915. }
  1916.  
  1917.  
  1918.  
  1919. /*
  1920.  *----------------------------------------------------------------------
  1921.  *
  1922.  * Ofs_ReallocBlock --
  1923.  *
  1924.  *    Allocate a new block on disk to replace the given block.  This is
  1925.  *    intended to be used by the cache when it can't write out a block
  1926.  *    because of a disk error.
  1927.  *
  1928.  * Results:
  1929.  *     None
  1930.  *
  1931.  * Side effects:
  1932.  *    The descriptor or indirect blocks are modified to point to the newly
  1933.  *    allocated block.
  1934.  *
  1935.  *----------------------------------------------------------------------
  1936.  */
  1937. /*ARGSUSED*/
  1938. void
  1939. Ofs_ReallocBlock(data, callInfoPtr)
  1940.     ClientData        data;            /* Block to move */
  1941.     Proc_CallInfo    *callInfoPtr;        /* Not used. */
  1942. {
  1943.     Fscache_Block     *blockPtr = (Fscache_Block *) data;
  1944.     Fscache_FileInfo    *cacheInfoPtr = blockPtr->cacheInfoPtr;
  1945.     Fsio_FileIOHandle    *handlePtr = (Fsio_FileIOHandle *) cacheInfoPtr->hdrPtr;
  1946.     int            virtBlockNum, physBlockNum;
  1947.     OfsBlockIndexInfo    indexInfo;
  1948.     Fsdm_Domain        *domainPtr;
  1949.     int            newBlockNum = -1;
  1950.     Boolean        dirtiedIndex = FALSE;
  1951.     Boolean        setupIndex = FALSE;
  1952.     unsigned char    *bitmapPtr;
  1953.     ReturnStatus    status;
  1954.     Fsdm_FileDescriptor    *descPtr;
  1955.     Ofs_Domain        *ofsPtr;
  1956. #ifdef SOSP91
  1957.     Boolean        isForeign = FALSE;    /* Due to migration? */
  1958. #endif SOSP91
  1959.  
  1960.     virtBlockNum = blockPtr->blockNum;
  1961.     physBlockNum = blockPtr->diskBlock;
  1962.     if (handlePtr->hdr.fileID.minor == 0) {
  1963.     /*
  1964.      * This is a descriptor block.
  1965.      */
  1966.     printf(
  1967.         "OfsBlockRealloc: Bad descriptor block.  Domain=%d block=%d\n",
  1968.           handlePtr->hdr.fileID.major, physBlockNum);
  1969.     goto error1;
  1970.     }
  1971.  
  1972.     domainPtr = Fsdm_DomainFetch(handlePtr->hdr.fileID.major, FALSE);
  1973.     if (domainPtr == (Fsdm_Domain *)NIL) {
  1974.     goto error;
  1975.  
  1976.     }
  1977.     ofsPtr = OFS_PTR_FROM_DOMAIN(domainPtr);
  1978.     Fsutil_HandleLock((Fs_HandleHeader *)handlePtr);
  1979.     descPtr = handlePtr->descPtr;
  1980.     if (virtBlockNum >= 0) {
  1981.     int        bytesInBlock;
  1982.     /*
  1983.      * A normal data block.
  1984.      */
  1985.     status = OfsGetFirstIndex(ofsPtr, handlePtr, virtBlockNum, &indexInfo, 0);
  1986.     if (status != SUCCESS) {
  1987.         printf( 
  1988.            "OfsBlockRealloc: Setup index (1) failed status <%x>\n", status);
  1989.         goto error;
  1990.     }
  1991.     setupIndex = TRUE;
  1992.     if (*indexInfo.blockAddrPtr != physBlockNum) {
  1993.         panic("OfsBlockRealloc: Bad physical block num.\n");
  1994.     }
  1995.     bytesInBlock = descPtr->lastByte - virtBlockNum * FS_BLOCK_SIZE + 1;
  1996.     if (bytesInBlock > FS_FRAGMENT_SIZE * (FS_FRAGMENTS_PER_BLOCK - 1) ||
  1997.         virtBlockNum >= FSDM_NUM_DIRECT_BLOCKS) {
  1998.         /* 
  1999.          * Have a full block.
  2000.          */
  2001.         OfsBlockFind(handlePtr->hdr.fileID.minor, ofsPtr,
  2002.             physBlockNum / FS_FRAGMENTS_PER_BLOCK, TRUE,
  2003.             &newBlockNum, &bitmapPtr);
  2004.         if (newBlockNum == -1) {
  2005.         printf( "FsdmBlockRealloc: No disk space (1)\n");
  2006.         goto error;
  2007.         }
  2008.         newBlockNum *= FS_FRAGMENTS_PER_BLOCK;
  2009.         *indexInfo.blockAddrPtr = newBlockNum;
  2010.         dirtiedIndex = TRUE;
  2011.         descPtr->flags |= FSDM_FD_INDEX_DIRTY;
  2012.         PutInBadBlockFile(handlePtr, ofsPtr, physBlockNum);
  2013.     } else {
  2014.         int    newFragOffset;
  2015.         int    numFrags;
  2016.         /*
  2017.          * Have a fragment.
  2018.          */
  2019.         numFrags = (bytesInBlock - 1) / FS_FRAGMENT_SIZE + 1;
  2020.         OfsFragFind(handlePtr->hdr.fileID.minor, ofsPtr, numFrags,
  2021.             -1, -1, -1, &newBlockNum, &newFragOffset);
  2022.         if (newBlockNum == -1) {
  2023.         printf( "FsdmBlockRealloc: No disk space (2)\n");
  2024.         goto error;
  2025.         }
  2026.         newBlockNum = newBlockNum * FS_FRAGMENTS_PER_BLOCK + newFragOffset;
  2027.         *indexInfo.blockAddrPtr = newBlockNum;
  2028.         dirtiedIndex = TRUE;
  2029.         descPtr->flags |= FSDM_FD_INDEX_DIRTY;
  2030.         if (OnlyFrag(ofsPtr, numFrags,
  2031.                physBlockNum / FS_FRAGMENTS_PER_BLOCK,
  2032.                physBlockNum & FRAG_OFFSET_MASK)) {
  2033.         PutInBadBlockFile(handlePtr, ofsPtr,
  2034.                   physBlockNum & ~FRAG_OFFSET_MASK);
  2035.         } else {
  2036.         /*
  2037.          * The fragment is in a block with other valid fragments.
  2038.          * We do nothing and just leave the fragment allocated
  2039.          * in the bitmap but unreferenced by any file.
  2040.          * This means checkFS should verify that an unreferenced
  2041.          * fragment is readable before marking it free.
  2042.          */
  2043.         printf( "Leaving bad frag #%d unreferenced\n",
  2044.                 physBlockNum);
  2045.         }
  2046.     }
  2047.     } else {
  2048.     Fscache_Block    *blockPtr = (Fscache_Block *)NIL;
  2049.     int        *blockAddrPtr;
  2050.  
  2051.     physBlockNum = -physBlockNum;
  2052.     if (virtBlockNum == -1) {
  2053.         /*
  2054.          * This is the first indirect block.
  2055.          */
  2056.         blockAddrPtr = &descPtr->indirect[0];
  2057.     } else if (virtBlockNum == -2) {
  2058.         /*
  2059.          * Second indirect block.
  2060.          */
  2061.         blockAddrPtr = &descPtr->indirect[1];
  2062.     } else if (descPtr->indirect[1] == FSDM_NIL_INDEX) {
  2063.         panic("OfsBlockRealloc: Can't find indirect block\n");
  2064.         blockAddrPtr = (int *) NIL;
  2065.     } else {
  2066.         Boolean    found;
  2067.         /*
  2068.          * Read in the doubly indirect block  so that we can get to the
  2069.          * indirect block that we want.
  2070.          */
  2071. #ifdef SOSP91
  2072.         if (proc_RunningProcesses[0] != (Proc_ControlBlock *) NIL) {
  2073.         if ((proc_RunningProcesses[0]->state == PROC_MIGRATED) ||
  2074.             (proc_RunningProcesses[0]->genFlags &
  2075.             (PROC_FOREIGN | PROC_MIGRATING))) {
  2076.             isForeign = TRUE;
  2077.         }
  2078.         }
  2079. #endif SOSP91
  2080.         fs_Stats.blockCache.indBlockAccesses++;
  2081. #ifdef SOSP91
  2082.         if (isForeign) {
  2083.         fs_SospMigStats.blockCache.indBlockAccesses++;
  2084.         }
  2085. #endif SOSP91
  2086.         Fscache_FetchBlock(&handlePtr->cacheInfo, -2,
  2087.             FSCACHE_IND_BLOCK, &blockPtr, &found);
  2088.         if (!found) {
  2089.         status = OfsDeviceBlockIO(ofsPtr, FS_READ,
  2090.                descPtr->indirect[1], FS_FRAGMENTS_PER_BLOCK, 
  2091.                blockPtr->blockAddr);
  2092.         if (status != SUCCESS) {
  2093.             printf( 
  2094.     "OfsBlockRealloc: Could not read doubly indirect block, status <%x>\n", 
  2095.             status);
  2096.             Fscache_UnlockBlock(blockPtr, 0, 0, 0, FSCACHE_DELETE_BLOCK);
  2097.             goto error;
  2098.         } else {
  2099.             fs_Stats.gen.physBytesRead += FS_BLOCK_SIZE;
  2100.         }
  2101.         } else {
  2102.         fs_Stats.blockCache.indBlockHits++;
  2103. #ifdef SOSP91
  2104.         if (isForeign) {
  2105.             fs_SospMigStats.blockCache.indBlockHits++;
  2106.         }
  2107. #endif SOSP91
  2108.         }
  2109.         blockAddrPtr = (int *)blockPtr->blockAddr + (-virtBlockNum - 3);
  2110.     }
  2111.     if (*blockAddrPtr != physBlockNum) {
  2112.         panic("OfsBlockRealloc: Bad phys addr for indirect block (2)\n");
  2113.     }
  2114.     /*
  2115.      * Allocate a new indirect block.
  2116.      */
  2117.     OfsBlockFind(handlePtr->hdr.fileID.minor, ofsPtr, -1, TRUE, 
  2118.             &newBlockNum, &bitmapPtr);
  2119.     if (newBlockNum == -1) {
  2120.         printf( "FsdmBlockRealloc: No disk space (3)\n");
  2121.         goto error;
  2122.     }
  2123.     newBlockNum = (newBlockNum + ofsPtr->headerPtr->dataOffset) * 
  2124.             FS_FRAGMENTS_PER_BLOCK;
  2125.     *blockAddrPtr = newBlockNum;
  2126.     if (blockPtr == (Fscache_Block *)NIL) {
  2127.         descPtr->flags |= FSDM_FD_INDEX_DIRTY;
  2128.     } else {
  2129.         Fscache_UnlockBlock(blockPtr, (unsigned int)Fsutil_TimeInSeconds(), 
  2130.                    -(descPtr->indirect[1]), FS_BLOCK_SIZE, 0);
  2131.     }
  2132.     PutInBadBlockFile(handlePtr, ofsPtr,
  2133.               physBlockNum - FS_FRAGMENTS_PER_BLOCK * 
  2134.                      ofsPtr->headerPtr->dataOffset);
  2135.     newBlockNum = -newBlockNum;
  2136.     }
  2137.  
  2138. error:
  2139.  
  2140.     if (setupIndex) {
  2141.     OfsEndIndex(handlePtr, &indexInfo, dirtiedIndex);
  2142.     }
  2143.     Fsdm_DomainRelease(handlePtr->hdr.fileID.major);
  2144.     Fsutil_HandleUnlock((Fs_HandleHeader *)handlePtr);
  2145. error1:
  2146.     FscacheFinishRealloc(blockPtr, newBlockNum);
  2147.     return;
  2148. }
  2149.  
  2150.  
  2151. /*
  2152.  *----------------------------------------------------------------------
  2153.  *
  2154.  * PutInBadBlockFile --
  2155.  *
  2156.  *    Put the given physical block into the bad block file.
  2157.  *
  2158.  * Results:
  2159.  *    None.
  2160.  *
  2161.  * Side effects:
  2162.  *    Block appended to the bad block file.
  2163.  *
  2164.  *----------------------------------------------------------------------
  2165.  */
  2166. static void
  2167. PutInBadBlockFile(handlePtr, ofsPtr, blockNum)
  2168.     Fsio_FileIOHandle    *handlePtr;    /* File which owned bad block. */
  2169.     Ofs_Domain    *ofsPtr;        /* Pointer to domain. */
  2170.     int        blockNum;    /* Block number to put in bad block file. */
  2171. {
  2172.     Fs_FileID        fileID;
  2173.     Fsio_FileIOHandle    *badBlockHandlePtr;
  2174.     Fsdm_FileDescriptor    *descPtr;
  2175.     OfsBlockIndexInfo    indexInfo;
  2176.     ReturnStatus    status;
  2177.     int            lastBlock;
  2178.  
  2179.     fileID.serverID = rpc_SpriteID;
  2180.     fileID.type = FSIO_LCL_FILE_STREAM;
  2181.     fileID.major = handlePtr->hdr.fileID.major;
  2182.     fileID.minor = OFS_BAD_BLOCK_FILE_NUMBER;
  2183.     badBlockHandlePtr = (Fsio_FileIOHandle *)Fsutil_HandleFetch(&fileID);
  2184.     if (badBlockHandlePtr == (Fsio_FileIOHandle *)NIL) {
  2185.     /*
  2186.      * Have to make a new handle since we don't have one for this domain
  2187.      * in memory.
  2188.      */
  2189.     status = Fsio_LocalFileHandleInit(&fileID, "BadBlockFile",
  2190.             (Fsdm_FileDescriptor *) NIL, FALSE, 
  2191.             &badBlockHandlePtr);
  2192.     if (status != SUCCESS) {
  2193.         printf("PutInBadBlockFile: error %x reading descriptor\n", status);
  2194.         return;
  2195.     }
  2196.     }
  2197.     descPtr = badBlockHandlePtr->descPtr;
  2198.     if (descPtr->lastByte != -1) {
  2199.     lastBlock = descPtr->lastByte / FS_BLOCK_SIZE;
  2200.     } else {
  2201.     lastBlock = -1;
  2202.     }
  2203.     status = OfsGetFirstIndex(ofsPtr, handlePtr, lastBlock + 1, &indexInfo,
  2204.                  OFS_ALLOC_INDIRECT_BLOCKS);
  2205.     if (status != SUCCESS) {
  2206.     printf( "PutInBadBlockFile: Could not fetch index\n");
  2207.     } else {
  2208.     *indexInfo.blockAddrPtr = blockNum;
  2209.     descPtr->lastByte += FS_BLOCK_SIZE;
  2210.     descPtr->flags |= (FSDM_FD_INDEX_DIRTY|FSDM_FD_SIZE_DIRTY);
  2211.     descPtr->numKbytes += FS_FRAGMENTS_PER_BLOCK;
  2212.     OfsEndIndex(handlePtr, &indexInfo, TRUE);
  2213.     }
  2214.  
  2215.     Fsutil_HandleUnlock((Fs_HandleHeader *)badBlockHandlePtr);
  2216. }
  2217.